package com.lcq.demo.service;

import com.lcq.demo.common.job.MyJob;
import com.lcq.demo.entity.po.ScheduleTask;
import com.lcq.demo.repository.ScheduleTaskRepository;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Service
public class ScheduleTaskService {

    @Autowired
    private ScheduleTaskRepository scheduleTaskRepository;
    @Autowired
    private Scheduler scheduler;
    @Autowired
    private ScheduleTaskLogService scheduleTaskLogService;

    public List<ScheduleTask> getTasks() {
        return scheduleTaskRepository.findAll();
    }

    public List<ScheduleTask> getExecutingTasks() {
        return scheduleTaskRepository.findByTaskStatus(1);
    }

    public void addTask(ScheduleTask task) {
        scheduleTaskRepository.save(task);
        scheduleTask(task);
    }

    public void updateTask(Long id, ScheduleTask task) {
        ScheduleTask existingTask = scheduleTaskRepository.findById(Math.toIntExact(id)).orElseThrow(() -> new RuntimeException("Task not found"));
        existingTask.setTaskName(task.getTaskName());
        existingTask.setCallTarget(task.getCallTarget());
        existingTask.setCronExpression(task.getCronExpression());
        existingTask.setTaskStatus(task.getTaskStatus());
        existingTask.setUpdatedTime(new Date());
        scheduleTaskRepository.save(existingTask);
        rescheduleTask(existingTask);
    }

    public void deleteTask(Long id) {
        ScheduleTask task = scheduleTaskRepository.findById(Math.toIntExact(id)).orElseThrow(() -> new RuntimeException("Task not found"));
        unscheduleTask(task);
        scheduleTaskRepository.deleteById(Math.toIntExact(id));
    }

    public void startTaskOnce(Long id) {
        ScheduleTask task = scheduleTaskRepository.findById(Math.toIntExact(id)).orElseThrow(() -> new RuntimeException("Task not found"));
        triggerTaskOnce(task);
    }

    public void stopTask(Long id) {
        ScheduleTask task = scheduleTaskRepository.findById(Math.toIntExact(id)).orElseThrow(() -> new RuntimeException("Task not found"));
        unscheduleTask(task);
    }

    public void startTask(Long id) {
        ScheduleTask task = scheduleTaskRepository.findById(Math.toIntExact(id)).orElseThrow(() -> new RuntimeException("Task not found"));
        scheduleTask(task);
    }

    private void scheduleTask(ScheduleTask task) {
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                .withIdentity(task.getTaskName(), "group1")
                .build();

        jobDetail.getJobDataMap().put("taskId", task.getId());

        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(task.getTaskName(), "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression()))
                .build();

        try {
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    private void rescheduleTask(ScheduleTask task) {
        try {
            scheduler.rescheduleJob(new TriggerKey(task.getTaskName(), "group1"), TriggerBuilder.newTrigger()
                    .withIdentity(task.getTaskName(), "group1")
                    .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression()))
                    .build());
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    private void unscheduleTask(ScheduleTask task) {
        try {
            scheduler.unscheduleJob(new TriggerKey(task.getTaskName(), "group1"));
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    private void triggerTaskOnce(ScheduleTask task) {
        JobDataMap dataMap = new JobDataMap();
        dataMap.put("taskId", task.getId());

        try {
            scheduler.triggerJob(new JobKey(task.getTaskName(), "group1"), dataMap);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }
}
